package demo1;

/**
 * 内存管理类，负责进程的内存分配和释放。
 * 使用PCB链表表示内存块，分为已占用和空闲块。
 */
public class Memory {
    // PCB头指针，表示系统进程（虚拟节点）
    private final PCB dummy;

    /**
     * 构造函数，初始化内存。
     * @param baseAddr 内存起始基址
     * @param capacity 内存总容量
     */
    public Memory(int baseAddr, int capacity) {
        // 创建虚拟头节点（系统进程）
        dummy = new PCB("系统进程", baseAddr, 0, true);
        // 初始时整个内存是一个空闲块
        dummy.setNext(new PCB(null, baseAddr, capacity, false));
    }

    /**
     * 将PCB添加到内存中，寻找第一个足够大的空闲块。
     * @param pcb 要分配内存的进程控制块
     * @return true：分配成功；false：分配失败（无足够空闲内存）
     */
    public boolean add(PCB pcb) {
        if (pcb == null) {
            System.out.println("无效PCB");
            return false;
        }

        PCB cur = dummy;
        PCB nextNode = dummy.getNext();
        PCB pre = dummy;
        PCB freeBlock = null; // 记录找到的空闲块

        // 遍历内存链表，寻找第一个足够大的空闲块
        while (nextNode != null) {
            if (!nextNode.isOccupied() && nextNode.getLength() >= pcb.getLength()) {
                pre = cur;
                freeBlock = nextNode;
                break; // 找到后退出循环
            }
            cur = nextNode;
            nextNode = nextNode.getNext();
        }

        if (freeBlock != null) {
            // 设置PCB的基址
            pcb.setBaseAddr(freeBlock.getBaseAddr());
            // 更新空闲块的长度
            freeBlock.setLength(freeBlock.getLength() - pcb.getLength());

            if (freeBlock.getLength() <= 2) {
                // 如果剩余空闲块太小（小于等于2），合并到PCB
                pcb.setLength(pcb.getLength() + freeBlock.getLength());
                pcb.setNext(freeBlock.getNext());
            } else {
                // 否则更新空闲块的基址，插入PCB
                freeBlock.setBaseAddr(pcb.getBaseAddr() + pcb.getLength());
                pcb.setNext(freeBlock);
            }

            // 将PCB插入链表
            pre.setNext(pcb);
            System.out.println("进程" + pcb.getId() + "已加入到内存中");
            return true;
        } else {
            System.out.println("内存不足！(无空闲内存)");
            return false;
        }
    }

    /**
     * 从内存中移除PCB，并合并相邻的空闲块。
     * @param pcb 要移除的进程控制块
     * @return true：移除成功；false：移除失败（未找到 PCB）
     */
    public boolean remove(PCB pcb) {
        if (pcb == null || dummy.getNext() == null) {
            System.out.println("内存无此进程");
            return false;
        }

        PCB current = dummy; // 当前节点
        PCB nextNode = dummy.getNext(); // 下一个节点

        while (nextNode != null) {
            if (pcb.getId().equals(nextNode.getId())) {
                // 如果下一个节点是空闲块，合并
                if (nextNode.getNext() != null && !nextNode.getNext().isOccupied()) {
                    nextNode.setLength(nextNode.getLength() + nextNode.getNext().getLength());
                    nextNode.setNext(nextNode.getNext().getNext());
                }
                // 如果前一个节点是空闲块
                if (!current.isOccupied()) {
                    current.setLength(current.getLength() + nextNode.getLength());
                    current.setNext(nextNode.getNext());
                } else {
                    // 否则标记当前块为空闲
                    nextNode.setOccupied(false);
                    nextNode.setId(null);
                }
                pcb.setOccupied(false);
                System.out.println("进程" + pcb.getId() + "已从内存中移除");
                return true;
            }
            current = nextNode;
            nextNode = nextNode.getNext();
        }

        System.out.println("无进程" + pcb.getId());
        return false;
    }

    /**
     * 显示内存中的所有PCB和空闲块信息。
     */
    public void show() {
        PCB current = dummy.getNext(); // 当前节点
        System.out.println("说明 : 进程标识<起始地址，结束地址>  (空闲块)");
        System.out.println("      (" + dummy.getId() + "<" + dummy.getBaseAddr() + "," + (dummy.getBaseAddr() + dummy.getLength()) + ">,长度" + dummy.getLength() + ") ");
        while (current != null) {
            if (!current.isOccupied()) {
                System.out.println("      (" + current.getLength() + ") ");
            } else {
                System.out.println("      (" + current.getId() + "<" + current.getBaseAddr() + "," + (current.getBaseAddr() + current.getLength()) + ">,长度" + current.getLength() + ") ");
            }
            current = current.getNext();
        }
        System.out.println();
        current = dummy.getNext();
        while (current != null) {
            if (!current.isOccupied()) {
                System.out.println("空闲空间:" + current.getBaseAddr() + "---" + (current.getBaseAddr() + current.getLength()));
            }
            current = current.getNext();
        }
        System.out.println();
    }
}